# Lucid is (C) Copyright 2006-2007 by Infiscape Corporation
#
# This file is part of Lucid, a PyOpenSG example application.
#
# Lucid is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# Lucid is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.

from PyQt4 import QtGui, QtCore
import osg2
from lucid.plugins.view.OpenSGTreeModel import OpenSGTreeModel
import tree_view_base
import lucid.core
from pydispatch import dispatcher


class TreeViewPlugin(lucid.core.IViewPlugin):
   def __init__(self):
      lucid.core.IViewPlugin.__init__(self)
      self.widget = TreeViewWidget(self)
      
      # Register callbacks
      #dispatcher.connect(self.onSceneAdd, lucid.core.signal.SceneAdded)
      dispatcher.connect(self.onSceneActivated, lucid.core.signal.ActiveSceneChanged)
      
      # Manually trigger activation of scene to get view up and running
      self.onSceneActivated()
   
   @staticmethod
   def getName():
      return "Tree View"
      
   def getViewWidget(self):
      return self.widget
      
   def onSceneActivated(self):
      env = lucid.core.Environment()
      active_scene = env.activeScene
      active_root = None
      if active_scene:
         active_root = active_scene.mSceneRoot
      self.widget.mOpenSGTreeModel.setRoot(active_root)
      # XXX: Fix this to get new model
      #self.widget.treeView.setRootIndex(x(self.model.indexOf(self.model.propRoot))      
   
   def getIcon(self):
      return QtGui.QIcon(":/icons/data/icons/treeview_16.png")


class TreeViewWidget(QtGui.QWidget, tree_view_base.Ui_Form):
   def __init__(self, plugin, parent=None):
      QtGui.QWidget.__init__(self, parent)
      self.setupUi(self)
      self.plugin = plugin
      
      # Create tree view of OpenSG scene graph.
      #self.mOpenSGTreeModel = OpenSGTreeModel(env.activeScene.mSceneRoot)
      self.mOpenSGTreeModel = OpenSGTreeModel(None)
      self.treeView.setModel(self.mOpenSGTreeModel)
      self.treeView.setDragEnabled(True)
      self.treeView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
      self.treeView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
      self.treeView.setAcceptDrops(True)
      self.treeView.setDropIndicatorShown(True)
      self.treeView.setAlternatingRowColors(True)
      self.treeView.setRootIsDecorated(True)
      #self.treeView.setMovement(Qt

      #self.treeView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu      )
      self.treeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)      
      self.treeView.connect(self.treeView,
                            QtCore.SIGNAL("customContextMenuRequested(QPoint)"),
                            self.contextMenuReq)
      
      # Register signal to highlight node.
      self.connect(self.treeView.selectionModel(),
         QtCore.SIGNAL("selectionChanged(QItemSelection,QItemSelection)"), self.onElementSelected)
      self.connect(self.mOpenSGTreeModel, QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.dataChanged_CB)
      
      # Setup the contained actions
      for a in [ ['mCopyAction', "Copy",self.copy, "Ctrl+C", 
                  "Make a shallow clone/copy of the tree nodes"],
                 ['mDeepCopyAction', "Deep Copy",self.copyDeep, "Ctrl+K", 
                  "Make a deep clone of the tree nodes and nodecores."],
                 ['mCutAction', "Cut",self.cut, "Ctrl+X", 
                  "Cut the tree rooted at the selected node."],
                 ['mPasteAction', "Paste",self.paste, "Ctrl+V", 
                  "Paste the current tree copy as a child of the current node."]]:
         (a_attrib,a_name, a_cb, a_shortcut, a_tooltip) = a
         action = QtGui.QAction(a_name,None)
         setattr(self,a_attrib,action)
         action.setShortcut(a_shortcut)
         action.setToolTip(a_tooltip)
         self.connect(action, QtCore.SIGNAL("triggered()"), a_cb)
         self.addAction(action)
      
      print "Done"
                 
   
   def contextMenuReq(self, pos):
      print "Requested context menu. ", pos

      index_pos = self.treeView.indexAt(self.treeView.mapFromGlobal(QtGui.QCursor.pos()))
      if index_pos.isValid():
         print "index pos: %s,%s"%(index_pos.row(),index_pos.column())
      else:
         print "index pos: invalid"
      
      index = self.treeView.currentIndex()
      if index.isValid():
         print "index: %s,%s"%(index.row(),index.column())
      else:
         print "index: invalid"
      
      menu = QtGui.QMenu(self)
      insert_menu = self.buildInsertMenu()
      create_menu = self.buildCreateMenu()
      menu.addMenu(insert_menu)
      menu.addMenu(create_menu)
      menu.addSeparator()
      menu.addAction(self.mCopyAction)
      menu.addAction(self.mDeepCopyAction)
      menu.addAction(self.mCutAction)
      menu.addAction(self.mPasteAction)
      menu.exec_(QtGui.QCursor.pos())
   
   def buildInsertMenu(self):
      """ Build up the menu of items that could be inserted. """
      node_cores = [c for c in osg2.__dict__.itervalues() if isinstance(c,type) \
                                             and (osg2.NodeCore in c.__mro__) \
                                             and (not c.__name__.endswith("Base")) \
                                             and (hasattr(c,"create"))]
      group_cores = [c for c in node_cores if issubclass(c,osg2.Group)]
      light_cores = [c for c in node_cores if issubclass(c,osg2.Light)]
      other_cores = [c for c in node_cores if (not c in group_cores) and (not c in light_cores)]

      self._insertCalls = []   # Store the lambdas that we create
      
      # Build up menu from lists of cores.
      # - Using lambda callables so we have to store them
      insert_menu = QtGui.QMenu("Insert")
      for g in [group_cores, light_cores, other_cores]:
         for c in g:
            insert_call = lambda ctype=c: self.insertCore(ctype)
            self._insertCalls.append(insert_call)
            insert_menu.addAction(c.__name__, insert_call)
         insert_menu.addSeparator()
      
      return insert_menu
      
   def buildCreateMenu(self):      
      env = lucid.core.Environment()
      create_plugins =  env.pluginManager.getPlugins(lucid.core.plugin_interfaces.IGraphCreatorPlugin)
      
      self._createCalls = []
      create_menu = QtGui.QMenu("Create")
      for p in create_plugins:
         create_call = lambda ptype=p: self.createGraph(ptype)
         create_menu.addAction(p.getName(), create_call)
         self._createCalls.append(create_call)
      
      return create_menu

   
   def createGraph(self, createPluginType):
      env = lucid.core.Environment()
      selected_node = env.selectedNode
      if not selected_node:
         print "Warning: No node selected.  Skipping create."
      else:
         new_node = createPluginType.createGraph()
         cur_scene = lucid.core.Environment().activeScene
         cur_scene.updateTypeMapFromFieldContainer(new_node)
         selected_node.addChild(new_node)      
         self.mOpenSGTreeModel.emit(QtCore.SIGNAL("layoutChanged()"))
      
   def onElementSelected(self, newSelection, oldSelection):
      print "Current row: %s" % (self.treeView.currentIndex().row())
      if len(newSelection.indexes()) > 0:
         index = newSelection.indexes()[0]
         selected_node = self.mOpenSGTreeModel.data(index,QtCore.Qt.UserRole)   
         if selected_node:
            print "Selected: %s:%s" % (selected_node, osg2.getName(selected_node))
         else:
            print "Selected: None"
      else:
         selected_node = None      
      lucid.core.Environment().selectedNode = selected_node
   
   #def copy(self):
      #self.mOpenSGTreeModel.copy()
   
   #def copyDeep(self):
      #self.mOpenSGTreeModel.copyDeep()
   
   #def cut(self):
      #self.mOpenSGTreeModel.cut()
   
   #def paste(self):
      #self.mOpenSGTreeModel.paste()
   
   #def insertCore(self, coreType):
      #self.mOpenSGTreeModel.insertCore(coreType)
      
   # ------------- Scene Editing --------------- #
   def copy(self):
      " Make a copy of the tree selected. "
      print "copy"
      cur_node = lucid.core.Environment().selectedNode      
      if cur_node:
         clone = osg2.cloneTree(cur_node)
         lucid.core.Environment().currentCopy = clone         
   
   def copyDeep(self):
      " Make a deep clone of the selected node. "
      print "copy deep"
      cur_node = lucid.core.Environment().selectedNode      
      if cur_node:
         clone = osg2.deepCloneTree(cur_node)
         lucid.core.Environment().currentCopy = clone
   
   def cut(self):
      " Cut the current node out of the tree and into current copy. "
      print "cut"
      cur_node = lucid.core.Environment().selectedNode
      if cur_node:
         lucid.core.Environment().currentCopy = cur_node
         parent = cur_node.getParent()
         if parent:
            parent.subChild(cur_node)
         cur_index = self.treeView.currentIndex()
         self.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), cur_index.parent(), cur_index.parent())
         self.mOpenSGTreeModel.emit(QtCore.SIGNAL("layoutChanged()"))
   
   def paste(self):
      " Paste the current copy into the tree. "
      print "paste"
      cur_node = lucid.core.Environment().selectedNode
      cur_copy = lucid.core.Environment().currentCopy
      if cur_node and cur_copy:
         cur_node.addChild(cur_copy)
         cur_index = self.treeView.currentIndex()         
         self.mOpenSGTreeModel.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), cur_index, cur_index)
         self.mOpenSGTreeModel.emit(QtCore.SIGNAL("layoutChanged()"))

   def insertCore(self, coreType):
      """ Insert a node with the given core at the current selected node. """
      print "Insert core: ", coreType
      cur_node = lucid.core.Environment().selectedNode
      if cur_node:
         new_node = osg2.Node.create()
         new_core = coreType.create()
         new_node.setCore(new_core)
         cur_node.addChild(new_node)
         cur_index = self.treeView.currentIndex()         
         self.mOpenSGTreeModel.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), cur_index, cur_index)         
         self.mOpenSGTreeModel.emit(QtCore.SIGNAL("layoutChanged()"))         

   def dataChanged_CB(self, tl, br):
      print "Data changed called."
